package cn.bonoon.kernel.web.html.grid;

import static cn.bonoon.kernel.util.StringHelper.isNotEmpty;

import java.lang.reflect.AnnotatedElement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.util.Assert;

import cn.bonoon.handler.impl.StandardAutoManager;
import cn.bonoon.kernel.IdGenerator;
import cn.bonoon.kernel.annotations.ResetProperty;
import cn.bonoon.kernel.descriptors.ObjectDescriptor;
import cn.bonoon.kernel.descriptors.UIPropertyAccessor;
import cn.bonoon.kernel.expression.IExpressionParameter;
import cn.bonoon.kernel.expression.QueryExpressionParameter;
import cn.bonoon.kernel.expression.QueryExpressionParameterMode;
import cn.bonoon.kernel.support.entities.Persistable;
import cn.bonoon.kernel.support.services.SearchService;
import cn.bonoon.kernel.util.StringHelper;
import cn.bonoon.kernel.web.ButtonEventType;
import cn.bonoon.kernel.web.KeyChecker;
import cn.bonoon.kernel.web.annotations.grid.AsColumn;
import cn.bonoon.kernel.web.annotations.grid.ColumnGroup;
import cn.bonoon.kernel.web.annotations.grid.GridButton;
import cn.bonoon.kernel.web.annotations.grid.GridOptions;
import cn.bonoon.kernel.web.annotations.grid.OperationType;
import cn.bonoon.kernel.web.controllers.BaseButtonResolver;
import cn.bonoon.kernel.web.controllers.GridButtonResolver;
import cn.bonoon.kernel.web.controllers.GridButtonStatus;
import cn.bonoon.kernel.web.controllers.GridSelectedType;
import cn.bonoon.kernel.web.controllers.GridToolbarResolver;
import cn.bonoon.kernel.web.handlers.ExecutableHandler;
import cn.bonoon.kernel.web.html.AbstractUIBuilder;
import cn.bonoon.kernel.web.html.InternalHtmlInfo;

/**
 * <pre>
 * 由于需要对按钮的操作权限进行判断，所以在生成grid的时候（可能是layout、也可以是iframe的模式）
 * 需要向model对象里注入一个用于判断当前用户操作权限的<code>keyChecker</code>对象，该对象
 * 必需实现<code>keyChecker.check(int key);</code>的方法。
 * </pre>
 * <pre>
 * 需要设置grid读取数据的路径{@link #setDataLoaderUrl(String)}；如果不设置，则无法读取数据；
 * 可以是自动解析的，也可以是自定义的数据加载路径
 * 可以向grid设置toolbar按钮{@link #addToolbar(GridButton)}
 * 和列表的botton按钮{@link #addButton(GridButton)}
 * 
 * 初始化函数使用{@link #internalInit(GridInitializer)}，初始化函数应该在{@link #parse()}之前被调用
 * 对整个界面的生成进行初始化
 * </pre>
 * @author jackson
 *
 */
public abstract class StandardGridBuilder extends AbstractUIBuilder implements IExpressionParameter{

	private final List<BaseColumn> columns = new ArrayList<BaseColumn>();
	private final List<BaseColumn> frozenColumns = new ArrayList<BaseColumn>();
	private Map<Integer, GridColumnGroup> groups;
	boolean hasColumnGroup = false, hasFrozenGroup = false;
	/**
	 * grid列表里按钮的样式
	 */
	private final String btncls = IdGenerator.fixed();
	
	/**
	 * 指定是否允许对行进行编辑
	 */
	private boolean rowEditable;
	
	protected Class<?> conditionClass;

	/**
	 * <pre>
	 * 定义在grid列表数据行里的操作按钮；
	 * 一般这些按钮都需要把所在列的数据的ID作为参数传到处理的控制器；
	 * 可以是弹出对话框、改变某行数据的状态等...
	 * </pre>
	 */
	protected final List<GridButtonResolver> buttons = new ArrayList<GridButtonResolver>();

	/**
	 * <pre>
	 * 定义在grid列表工具栏上的操作按钮；
	 * 这些按钮可以不传任何的参数，如：打开新建对话框等
	 * 也可以根据列表所选中的数据，把所选中的ID传给处理控制器，如：批量删除等操作
	 * </pre>
	 */
	protected final List<GridToolbarResolver> toolbar = new ArrayList<GridToolbarResolver>();
	
	/**
	 * <pre>
	 * 向列表中的记录添加一个该记录的操作按钮
	 * 
	 * 在执行{@link #parse()}方法之前就应该添加按钮
	 * </pre>
	 * @return
	 * @see GridButtonResolver
	 */
	public GridButtonResolver addButton(){
		GridButtonResolver btn = new GridButtonResolver(id);
		buttons.add(btn);
		return btn;
	}
	
	/**
	 * <pre>
	 * 向列表的toolbar栏上添加一个按钮
	 * 
	 * 在执行{@link #parse()}方法之前就应该添加按钮
	 * </pre>
	 * @return
	 * @see GridToolbarResolver
	 */
	public GridToolbarResolver addToolbar(){
		GridToolbarResolver btn = new GridToolbarResolver(id);
		toolbar.add(btn);
		return btn;
	}
	
	@Override
	public boolean parse() throws Exception{ 
		__parse(html); 
		_parseDataFunction(html, queryParams);
		return false;
	}
	
	protected StringBuilder _parseDataFunction(InternalHtmlInfo html, List<QueryExpressionParameter> qps){
		StringBuilder script = html.getScript();
		script.append("function ").append(_dataFunction).append("(){return {");
		if(null != qps){
			char c = ' ';
			for(QueryExpressionParameter qp : qps){
				qp.parameter(script.append(c));
				c = ',';
			}
		}
		return script.append("};}");
	}

	private StringBuilder _parseGridColumn(StringBuilder mainColumn, List<BaseColumn> columns) {
		StringBuilder subColumns = null;
		for (BaseColumn bc : columns) {
			if (bc.valid) {
				bc.toColumn(mainColumn);
				if (bc instanceof GridColumnGroup) {
					if (null == subColumns){
						subColumns = new StringBuilder();
					}//TODO ORDER
					List<GridColumn> cls = ((GridColumnGroup) bc).columns;
					Collections.sort(cls);
					for (GridColumn gc : cls) {
						gc.toColumn(subColumns);
					}
				}
			}
		}
		return subColumns;
	}

	protected String gridType;
	
	/**
	 * <pre>
	 * 列表的类型，目前有两种：datagrid/treegrid
	 * 
	 * 列表的类型在执行{@link #init(Class, GridInitializer)}初始化函数之后才能确定
	 * </pre>
	 * @return
	 */
	public final String getGridType(){
		return gridType;
	}

	//把界面的查询条件值转成json格式的对象，并使用查询条件的参数值给控制器
	protected final String _dataFunction = IdGenerator.fixed();
	
	/**
	 * <pre>
	 * 列表中默认的查询条件的值
	 * 
	 * 当在生成grid界面的时候，会把"queryParams"参数转成界面取值的javascript代码或url参数；
	 * 接收者是自动加载值的处理handler，在具体的handler里取值，并生成相应的数据查询语句来加载对象
	 * </pre>
	 */
	protected List<QueryExpressionParameter> queryParams;
	/**
	 * <pre>
	 * js语句的查询语句
	 * 
	 * 查询语句在初始化函数{@link #init(Class, GridInitializer)}被调用之前进行赋值
	 * 因为初始化函数的操作可能需要用到这些参数来生成自动加载数据的处理器
	 * </pre>
	 * @param qlExpression 查询语句的表达式，如：x.role.id={rid}等
	 * @param valueExpression 界面取值的表达式，如：jQuery('#xxxid').val()等
	 */
	public void addQueryParameter(String qlExpression, String valueExpression) {
		__addQueryParameter(new QueryExpressionParameter(qlExpression, valueExpression));
	}
	
	@Override
	public void addQueryParameter(String qlExpression, String valueExpression, QueryExpressionParameterMode type) {

		__addQueryParameter(new QueryExpressionParameter(qlExpression, valueExpression, type));
	}
	
	@Override
	public void addQueryParameter(QueryExpressionParameter qp){
		if(null != qp){
			__addQueryParameter(qp);
		}
	}
	
	public void addQueryParameters(List<QueryExpressionParameter> parameters){
		if(null != parameters && !parameters.isEmpty()){
			_checked();
			queryParams.addAll(parameters);
		}
	}
	
	private void _checked(){
		if(null == queryParams){
			queryParams = new ArrayList<QueryExpressionParameter>(2);
		}
	}
	private void __addQueryParameter(QueryExpressionParameter qp){
		_checked();
		queryParams.add(qp);
	}
	
	/**
	 * <pre>
	 * 加载grid数据的路径；
	 * 可以是自动生成的，也可以是自己写控制器然后在子类中指定位置
	 * </pre>
	 */
	private String dataLoaderUrl;
	
	/**
	 * 重新加载列表
	 */
	private String gridReload;
	
	/**
	 * <pre>
	 * 重新加载列表
	 * 
	 * js语句，格式如：jQuery('#id').bupgrid('reload') 
	 * 或 jQuery('#id').treegrid('reload')
	 * 
	 * 列表的类型在执行{@link #init(Class, GridInitializer)}初始化函数之后才能确定
	 * </pre>
	 * @return
	 */
	public String getGridReload() {
		return gridReload;
	}
	
	/**
	 * <pre>
	 * 可以放到缓存被重用的
	 * 
	 * velocity需要赋值的字段：
	 */
	public StandardGridBuilder(String gridType, GridOptions grid, ObjectDescriptor descriptor, StandardAutoManager manager){
		super(descriptor, manager);
		__init(gridType, grid);
	}
	
	/**
	 * 不可以被重用的
	 * 
	 * 内部使用
	 * @param id
	 */
	public StandardGridBuilder(String gridType, GridOptions grid, ObjectDescriptor descriptor, StandardAutoManager manager, InternalHtmlInfo html){
		super(descriptor, manager, html);
		__init(gridType, grid);
	}
	
	/**
	 * 初始化函数，此函数将在对象创建的时候被调用
	 * @param gridType
	 */
	protected void __init(String gridType, GridOptions grid){
		this.gridType = gridType;
		this.gridReload = "jQuery('#" + id + "')." + gridType + "('reload');";
		if(null != grid){
			singleSelect = grid.singleSelect();
			rownumbers = grid.rownumbers();
			fitColumns = grid.fitColumns();
			
			sortName = grid.sortName();
			//TODO 取column的值
//			for (UIPropertyAccessor accessor : uiDescriptor.values()) {
//				AsColumn column = accessor.getAnnotation(AsColumn.class);
//				if(column.orderBy().isEmpty()){
//					sortName = grid.sortName();
//				}else{
//					sortName = column.orderBy();
//				}
//			}
			sortOrder = grid.sortOrder();
			checkbox = grid.checkbox();
			
			operation = grid.operation();
			if(operation != OperationType.NONE){
				operationField = grid.operationField();
				operationTitle = grid.operationTitle();
				operationWith = grid.operationWith();
			}
			int groupSize = grid.groups().length;
			if (groupSize > 0) {
				groups = new HashMap<Integer, GridColumnGroup>(groupSize);
				for (int i = 0; i < groupSize; i++) {
					ColumnGroup cg = grid.groups()[i];
					GridColumnGroup gcg = new GridColumnGroup(cg);
					groups.put(i + 1, gcg);
					if (cg.frozen()) {
						frozenColumns.add(gcg);
						hasFrozenGroup = true;
					} else {
						columns.add(gcg);
						hasColumnGroup = true;
					}
				}
			}
		}else{
			checkbox = false;
			singleSelect = false;
			rownumbers = false;
			fitColumns = false;
			operation = OperationType.NONE;
			sortName = "id";
			sortOrder = "desc";
		}
		
		for (UIPropertyAccessor accessor : uiDescriptor.values()) {
			AsColumn column = accessor.getAnnotation(AsColumn.class);
			if (null != column) {
				String opn = accessor.getName();
				GridColumn gc = new GridColumn(column, opn);
				Integer g = column.group();
				if (null != groups && g > 0 && groups.containsKey(g)) {
					GridColumnGroup gcg = groups.get(g);
					gc.group = gcg;
					/*
					 * 如果为一个column指定了所属的组，则该column里的frozen字段将会根据该
					 * 组的frozen字段赋值,即column里的frozen字段无效。
					 */
					gcg.columns.add(gc);
				} else if (column.frozen()) {
					frozenColumns.add(gc);
				} else {
					columns.add(gc);
				}
			}
		}
	}
	
	public StandardGridBuilder initLoader(String dataLoaderUrl){
		Assert.notNull(dataLoaderUrl, "没有定义加载列表数据的控制器！");
		this.dataLoaderUrl = dataLoaderUrl;
		return this;
	}
	
	/**
	 * <pre>
	 * 只用来解释和初始化一些工作，不应该用来生成界面
	 * 
	 * 赋值工作应该在调用初始化函数之前完成，如：{@link #addQueryParams(String, String)}
	 * </pre>
	 * @param conditionClass
	 * @param gridInitializer
	 */
	public <E extends Persistable> StandardGridBuilder initLoader(SearchService<E> searchService, AnnotatedElement aEle) throws Exception{
		ExecutableHandler handler = __loader(searchService, aEle);

		manager.register(handler);
		dataLoaderUrl = handler.getUrl();
		return this;
	}
	
	protected abstract <E extends Persistable> ExecutableHandler __loader(SearchService<E> searchService, AnnotatedElement aEle)throws Exception;
		
	private boolean singleSelect, rownumbers, fitColumns;
	private OperationType operation;
	private String sortName, sortOrder;
		
	/**
	 * 默认情况下，datagrid为true，treegrid为false；
	 */
	private boolean checkbox;
		
	protected String idField;
	protected String operationField;
	protected String operationTitle;
	protected int operationWith;

	/**
	 * {@link #__parse(InternalHtmlInfo)}里调用
	 * @param html
	 * @param gridAttribute
	 */
	protected void initGridAttribute(InternalHtmlInfo html, StringBuilder gridAttribute){
		
		html.append(" id='").append(id).append("'");
		gridAttribute.append(", url:'").append(dataLoaderUrl);
		gridAttribute.append("', idField:'").append(idField);
		gridAttribute.append("', sortField:'").append(sortName);
		gridAttribute.append("', sortOrder:'").append(sortOrder);
		gridAttribute.append("', remoteSort:true, fit:true, singleSelect:false");
		if (rownumbers) {
			gridAttribute.append(", showRownum:true"); // rownumbers
		}
		if (singleSelect) {
			gridAttribute.append(", singleSelect:true");
		}
		if (fitColumns) {
			gridAttribute.append(", fitColumns:true");
		} else {
			gridAttribute.append(", fitColumns:false");
		}
	}
	
	/**
	 * 在{@link #parse()}里调用
	 * @param html
	 */
	protected void __parse(InternalHtmlInfo html){
		StringBuilder gattrs = new StringBuilder();
		gattrs.append("jQuery('#").append(id).append("').").append(gridType);
		gattrs.append("({onLoadSuccess:function(){jQuery('.").append(btncls);
		gattrs.append("').click(function(e){return false;});}, queryParams:").append(_dataFunction).append("()");
		html.append("<table");
		
		initGridAttribute(html, gattrs);
		html.append('>');

		// 处理frozenColumns
		if (operation == OperationType.LEFT || !frozenColumns.isEmpty()) {
			html.append("<thead frozen='true'><tr>");
			Collections.sort(frozenColumns);// 排序
			
			StringBuilder mainColumn = new StringBuilder();
			StringBuilder subColumns = _parseGridColumn(mainColumn, frozenColumns);
			if (operation == OperationType.LEFT && !buttons.isEmpty()) {
				html.append("<th ");
				if (operationWith > 0){
					html.append(" width='").append(operationWith);
				}
				if (null != subColumns){
					html.append("' rowspan='2");
				}
				html.append("' data-settings=\"field:'").append(operationField);
				html.append("',sortable:false, formatter:function(value,row,index){var __internalButton='';");
				
				//TODO 这里添加是否显示某个按钮的设置
				//有操作按钮的情况
				Collections.sort(buttons);
				for(GridButtonResolver button : buttons){
					String rtkey = button.getCloseButtonKey();
					if(StringHelper.isEmpty(rtkey)){
						__button(html, button);
					}else{
						html.append(" #if(!$").append(rtkey).append(")");
						__button(html, button);
						html.append(" #end ");
					}
				}
				html.append(";return __internalButton;}\">").append(operationTitle).append("</th>");
			}
			html.append(mainColumn);
			
			html.append("</tr>");
			if (null != subColumns){
				//sbsc.append(subColumns);
				html.append("<tr>").append(subColumns).append("</tr>");
			}
			html.append("</thead>");
//		} else if (checkbox) {//<thead></thead>
//			html.append("<th data-settings=\"field:'checked', checkbox:true\"></th>");
		}

		// 处理columns
		if (!columns.isEmpty()) {
			html.append("<thead><tr>");
			
			Collections.sort(columns);// 排序
			StringBuilder mainColumn = new StringBuilder();
			StringBuilder subColumns = _parseGridColumn(mainColumn, columns);
			
//			if (operation == OperationType.LEFT && !buttons.isEmpty()) {
//				html.append("<th ");
//				if (operationWith > 0){
//					html.append(" width='").append(operationWith);
//				}
//				if (null != subColumns){
//					html.append("' rowspan='2");
//				}
//				html.append("' data-settings=\"field:'").append(operationField).append("',sortable:false, formatter:function(value,row,index){var __internalButton='';");
//				
//				//TODO 这里添加是否显示某个按钮的设置
//				//有操作按钮的情况
//				Collections.sort(buttons);
//				for(GridButtonResolver button : buttons){
//					String rtkey = button.getCloseButtonKey();
//					if(StringHelper.isEmpty(rtkey)){
//						__button(html, button);
//					}else{
//						html.append(" #if(!$").append(rtkey).append(")");
//						__button(html, button);
//						html.append(" #end ");
//					}
//				}
//				html.append(";return __internalButton;}\">").append(operationTitle).append("</th>");
//			}
			
			if(checkbox && frozenColumns.isEmpty()){
				html.append("<th data-settings=\"field:'checked', checkbox:true\"");
				if (null != subColumns){
					html.append(" rowspan='2'");
				}
				html.append("></th>");
			}

			//
			html.append(mainColumn);
			
			// 操作按钮
			if (operation == OperationType.RIGHT && !buttons.isEmpty()) {
				html.append("<th ");
				if (operationWith > 0){
					html.append(" width='").append(operationWith);
				}
				if (null != subColumns){
					html.append("' rowspan='2");
				}
				html.append("' data-settings=\"field:'").append(operationField).append("',sortable:false, formatter:function(value,row,index){var __internalButton='';");
				
				//TODO 这里添加是否显示某个按钮的设置
				//有操作按钮的情况
				Collections.sort(buttons);
				for(GridButtonResolver button : buttons){
					String rtkey = button.getCloseButtonKey();
					if(StringHelper.isEmpty(rtkey)){
						__button(html, button);
					}else{
						html.append(" #if(!$").append(rtkey).append(")");
						__button(html, button);
						html.append(" #end ");
					}
				}
				html.append(";return __internalButton;}\">").append(operationTitle).append("</th>");
			}

			//TODO 这里需要处理是否允许在grid上对行进行编辑的情况
//			if(rowEditable){
//				String did = IdGenerator.fixed();
//				gattrs.append(",onBeforeEdit:function(index,row){jQuery('#").append(id);
//				gattrs.append("').").append(gridType);
//				gattrs.append("('updateRow',{index: index,row:{}});},onAfterEdit:function(index,row){jQuery('#").append(id);
//				gattrs.append("').").append(gridType);
//				gattrs.append("('updateRow',{index: index,row:{}});},onCancelEdit:function(index,row){jQuery('#").append(id);
//				gattrs.append("').").append(gridType);
//				gattrs.append("('updateRow',{index: index,row:{}});},onDblClickRow:function(index,row){var oldIndex=jQuery('#").append(id);
//				gattrs.append("').data('").append(did);
//				gattrs.append("');if(index===oldIndex){jQuery('#").append(id);
//				gattrs.append("').").append(gridType);
//				gattrs.append("('endEdit',index);jQuery('#").append(id);
//				gattrs.append("').data('").append(did);
//				gattrs.append("', -1);}else{if(oldIndex>0){jQuery('#").append(id);
//				gattrs.append("').").append(gridType);
//				gattrs.append("('endEdit',oldIndex);}jQuery('#").append(id);
//				gattrs.append("').").append(gridType);
//				gattrs.append("('beginEdit',index);jQuery('#").append(id);
//				gattrs.append("').data('").append(did);
//				gattrs.append("', index);}}");
//			}
			

			html.append("</tr>");
			if (null != subColumns){
				//sbsc.append(subColumns);
				html.append("<tr>").append(subColumns).append("</tr>");
			}
			html.append("</thead>");
		}
		//html.append("</tr>");
		//if(sbsc.length() > 0){
		//html.append("<tr>").append(sbsc).append("</tr>");
		//}
		//html.append("</thead>");
		html.append("</table>");
		String tid = parseToolbar(html);
		if(null != tid){
			gattrs.append(", toolbar:'#").append(tid).append("'");
		}
		gattrs.append(",checkOnSelect:false,onLoadError:__ajaxError");
		parseGridAttrs(gattrs);
		gattrs.append("});");
		html.getBlock().append(gattrs);
	}

	private void __button(InternalHtmlInfo html, GridButtonResolver button) {
		int key = button.getKey();
		if(key > 0){
			html.append(" #if(${").append(KeyChecker.CHECKER_PROPERTY_NAME).append(".check(").append(key).append(")}) ");
			buildButton(button, html);
			html.append(" #end ");
		}else{
			buildButton(button, html);
		}
	}
	
	protected void parseGridAttrs(StringBuilder gattrs){}
	
	protected abstract String parseToolbar(InternalHtmlInfo html);
	
	/* ****************************************************************************
	 * 
	 * 在button或toolbar按钮操作完成后，都应该对grid(datagrid,treegrid)列表进行刷新，重新加载数据；
	 * 刷新有两种方式：
	 * 1.使用load     刷新并且中转到第一页
	 * 2.使用reload   重新加载当前页的数据
	 * 
	 * 通常情况下，添加操作可以使用load，添加完记录并且自动跳转到第一页，默认是按创建时间排序，这样才能看到添加的记录
	 * 其它操作都应该使用reload在当前页面刷新数据
	 * 
	 * ****************************************************************************/
	
	protected void buildButton(GridButtonResolver button, InternalHtmlInfo html){
		GridButtonStatus buttonStatus = button.getButtonStatus();//是否需要使用状态来控制按钮的处理
		if(null != buttonStatus && buttonStatus.ckeckStatus()){
			int[] status = buttonStatus.getStatus();
			String prop = buttonStatus.getProperty();
			html.append(";if(").append(status[0]).append("==row.").append(prop);
			for(int i = 1; i < status.length; i++){
				html.append(" || ").append(status[i]).append("==row.").append(prop);
			}
			html.append("){");
			parseButton(button, html);
			html.append("}");
		}else{
			parseButton(button, html);
		}
	}
	
	protected void initToolbar(InternalHtmlInfo html){
		Collections.sort(toolbar);
		//TODO 这里添加可以根据状态或当前具体情况，控制哪些按钮是否显示
		for (GridToolbarResolver button : toolbar) {
			//通过velocity来控制访问的权限
			String rtkey = button.getCloseButtonKey();
			if(StringHelper.isEmpty(rtkey)){
				__toolbar(html, button);
			}else{
				html.append(" #if(!$").append(rtkey).append(")");
				__toolbar(html, button);
				html.append(" #end ");
			}
		}
	}

	private void __toolbar(InternalHtmlInfo html, GridToolbarResolver button) {
		int key = button.getKey();
		if(key > 0){
			html.append(" #if(${").append(KeyChecker.CHECKER_PROPERTY_NAME).append(".check(").append(key).append(")})");
			buildToolbar(button, html);
			html.append(" #end ");
		}else{
			buildToolbar(button, html);
		}
	}
	
	private void parseButton(GridButtonResolver button, InternalHtmlInfo html){
		String name = button.getName();
		String title = button.getTitle();
		if(StringHelper.isEmpty(title)){
			title = name;
		}
		String funName = button.getFunctionName();
		//js源码
		StringBuilder js = html.getScript();
		if(StringHelper.isNotEmpty(funName)){
			/*
			 * 如果定义了js函数名，则有两种情况：
			 * 1.定义了函数体；如果定义了函数体，则直接使用该函数体hj 
			 * 2.没有定义函数体；如果函数体没有定义，则认为该函数在其它地方定义了，这里将直接引用该函数
			 */
			if(StringHelper.isEmpty(button.getFunctionBody())){
				_buttonEvent(js, button, funName);
			}
		}else{
			funName = IdGenerator.fixed();//MD5Util.getMD5("fun_0_" + id + "_" + index);
			/*
			 * 没有定义函数名和函数体，有两种情况：
			 * 1.该按钮定义的是一个普通的操作按钮，则直接使用ajax的post提交
			 * 2.该按钮定义的是一个弹出对话框按钮，则需要使用div.load来加载并弹出对话框
			 */
			_buttonEvent(js, button, funName);
		}
		
		//html源码
		String url = button.getUrl();
		html.append("__internalButton+='&lt;a href=&quot;").append(url);
		String sp = url.indexOf('?') !=-1 ? "&amp;" : "?";
		List<QueryExpressionParameter> parameters = button.getParameters();
		if(null == parameters || parameters.isEmpty()){
			html.append(sp).append("id='+value");
		}else{
			for(QueryExpressionParameter parameter : parameters){
				parameter.value(html.append(sp).append(parameter.getName()).append("='+row['"));
				html.append("']");
				sp = "&amp;";
			}
		}
		if(button.isPassByParameter()){
			html.append("+'&amp;gridid=").append(id);
		}else{
			html.append("+'");
		}
		html.append("&quot; title=&quot;").append(title).append("&quot;");
		if(button.clickable()){
			html.append(" class=&quot;").append(btncls).append("&quot;");
			html.append(" onclick=&quot;return ").append(funName).append(".call(this);&quot;");
		}else if(button.getEventType() == ButtonEventType.JUMP){
			html.append(" target=&quot;_banlk&quot;");
		}
		html.append("&gt;").append(name).append("&lt;/a&gt;&nbsp;';");
	}

	private void _buttonEvent(StringBuilder js, GridButtonResolver button, String funName) {
		js.append("function ").append(funName).append("(){var __grid='").append(id).append("';");
		button.event(js, button.getFunctionBody(), gridReload);
		js.append("}");
	}
	
	private void buildToolbar(GridToolbarResolver button, InternalHtmlInfo html){
		//js源码
		String bid = IdGenerator.fixed();
		String funName = button.getFunctionName();
		StringBuilder block = html.getBlock();
		block.append("jQuery('#").append(bid).append("').click(");
		if(StringHelper.isNotEmpty(funName)){
			/*
			 * 如果定义了js函数名，则有两种情况：
			 * 1.定义了函数体；如果定义了函数体，则直接使用该函数体hj 
			 * 2.没有定义函数体；如果函数体没有定义，则认为该函数在其它地方定义了，这里将直接引用该函数
			 */
			if(StringHelper.isNotEmpty(button.getFunctionBody())){
				StringBuilder js = html.getScript();
				js.append("function ").append(funName);
				_toolbarEvent(js, button);
			}
			block.append(funName);
		}else{
			/*
			 * 没有定义函数名和函数体，有两种情况：
			 * 1.该按钮定义的是一个普通的操作按钮，则直接使用ajax的post提交
			 * 2.该按钮定义的是一个弹出对话框按钮，则需要使用div.load来加载并弹出对话框
			 */
			_toolbarEvent(block.append("function"), button);
		}
		block.append(");");
		
		//html源码
		button.button(html.getHtml(), bid);
	}
	
	private void _toolbarEvent(StringBuilder js, GridToolbarResolver button){
		js.append("(){var __grid='").append(id).append("';");
		__parseData(button, js);
		button.event(js, button.getFunctionBody(), gridReload);
		js.append('}');
	}
	
	private void __parseData(GridToolbarResolver button, StringBuilder js) {
		GridSelectedType selectedType = button.getSelectedType();
		if(selectedType == GridSelectedType.MULTIPLE){
			multipleSelect(js, button, button.getButtonStatus());
		}else if(selectedType == GridSelectedType.SINGLE){
			singleSelect(js, button, button.getButtonStatus());
		}else{
			js.append("var __data={};");
			String body = button.getFunctionBody();
			if(null != body){
				js.append(body);
			}
		}
	}
	
	/**
	 * <pre>
	 * 当前列表有且只有一个被选中的情况；
	 * 返回的被选中的row的id存在__data字段中；
	 * __data字段中存储的格式为：__data={id:id}
	 * 如果外部需要向处理控制器发送更多的内容，可以向__data添加更多的属性；
	 * 如：__data["name"] = "china"等
	 * 
	 * 列表的类型在执行{@link #init(Class, GridInitializer)}初始化函数之后才能确定
	 * </pre>
	 * @param js
	 * @param button
	 * @param status
	 */
	public void singleSelect(StringBuilder js, BaseButtonResolver button, GridButtonStatus status){
		__parseData("__single", js, button, status);
	}
	
	/**
	 * <pre>
	 * 选择多个行的情况；
	 * 返回的被选中的row的id存在__data字段中；
	 * __data字段中存储的格式为：__data={ids:ids}
	 * 如果外部需要向处理控制器发送更多的内容，可以向__data添加更多的属性
	 * 如：__data["name"] = "china"等
	 * 
	 * 列表的类型在执行{@link #init(Class, GridInitializer)}初始化函数之后才能确定
	 * </pre>
	 * @param js
	 * @param button
	 * @param status
	 */
	public void multipleSelect(StringBuilder js, BaseButtonResolver button, GridButtonStatus status){
		__parseData("__multiple", js, button, status);
	}
	
	private void __parseData(String fun, StringBuilder js, BaseButtonResolver button, GridButtonStatus buttonStatus) {
		js.append("var __data=jQuery('#").append(id).append("').");
		js.append(fun).append("('").append(gridType).append("','").append(button.getName()).append('\'');
		if(null != buttonStatus && buttonStatus.ckeckStatus()){
			int[] status = buttonStatus.getStatus();
			js.append(",'").append(buttonStatus.getProperty());
			js.append("',[").append(status[0]);
			for(int i = 1; i < status.length; i++){
				js.append(",").append(status[i]);
			}
			js.append(']');
		}
		js.append(");if(!__data){return false;}");
	}
	
	protected abstract class BaseColumn implements Comparable<BaseColumn> {
		protected int ordinal = 0;
		//protected boolean isFrozen = false;
		@Override
		public int compareTo(BaseColumn o) {
			return ordinal - o.ordinal;
		}

		protected abstract void toColumn(StringBuilder col);

		/**
		 * 是否有效，即该字段有问题或者是组但组下没有任何的字段，则应该跳过该列
		 */
		protected boolean valid = true;
	}

	protected class GridColumnGroup extends BaseColumn {
		protected GridColumnGroup(ColumnGroup columnGroup) {
			this.columnGroup = columnGroup;
			this.ordinal = columnGroup.ordinal();
			//this.isFrozen = columnGroup.frozen();
		}

		protected ColumnGroup columnGroup;

		protected List<GridColumn> columns = new ArrayList<GridColumn>();

		@Override
		protected void toColumn(StringBuilder col) {
			col.append("<th colspan='").append(columns.size());
			col.append("'>").append(columnGroup.value()).append("</th>");
		}
	}

	protected class GridColumn extends BaseColumn {
		protected GridColumn(AsColumn asColumn, String field) {
			this.field = field;
			this.asColumn = asColumn;
			if (null != asColumn)
				ordinal = asColumn.ordinal();
		}

		protected String field;
		protected AsColumn asColumn;
		protected GridColumnGroup group;

		@Override
		protected void toColumn(StringBuilder col) {
			col.append("<th");
			if (null == group){
				if(null != groups && !groups.isEmpty()){
					if(asColumn.frozen()){
						if(hasFrozenGroup){
							col.append(" rowspan='2'");
						}
					}else if(hasColumnGroup){
						col.append(" rowspan='2'");
					}
				}
			}
			col.append(" data-settings=\"field:'").append(field);
			
			if (asColumn.sortable()){
				col.append("', sortable:'true");
			}
			col.append("', align:'").append(asColumn.align());
			if (isNotEmpty(asColumn.formatter())){
				col.append("', formatter:'").append(asColumn.formatter());
			}
			if (isNotEmpty(asColumn.editor())){
				col.append("', editor:'").append(asColumn.editor());
				//这里是允许使用grid编辑字段的情况
				rowEditable = true;
			}
			if (isNotEmpty(asColumn.styler())){
				col.append("', styler:'").append(asColumn.styler());
			}
			if (isNotEmpty(asColumn.sorter())){
				col.append("', sorter:'").append(asColumn.sorter());
			}
			if (asColumn.width() > 0){
				col.append("', width:").append(asColumn.width());
			}
			col.append("\">");
			
//			col.append("<th field='").append(field);
//			if (null == group && null != groups && !groups.isEmpty()){
//				col.append("' rowspan='2");
//			}
//			if (asColumn.sortable()){
//				col.append("' sortable='true");
//			}
//			col.append("' align='").append(asColumn.align());
//			if (isNotEmpty(asColumn.formatter())){
//				col.append("' formatter='").append(asColumn.formatter());
//			}
//			if (isNotEmpty(asColumn.editor())){
//				col.append("' editor='").append(asColumn.editor());
//				//这里是允许使用grid编辑字段的情况
//				rowEditable = true;
//			}
//			if (isNotEmpty(asColumn.styler())){
//				col.append("' styler='").append(asColumn.styler());
//			}
//			if (isNotEmpty(asColumn.sorter())){
//				col.append("' sorter='").append(asColumn.sorter());
//			}
//			if (asColumn.width() > 0){
//				col.append("' width='").append(asColumn.width());
//			}
//			col.append("'>");
			String name = null;
			if(StringHelper.isEmpty(name)){
				name = asColumn.name();
			}
			if(StringHelper.isEmpty(name)){
				ResetProperty pr = uiDescriptor.getPropertyReseter(field);
				if(null != pr){
					name = pr.name();
				}
			}
			if(StringHelper.isEmpty(name)){
				name = field;
			}
			col.append(name).append("</th>");
		}
	}
}
